package com.yenlien.traceyun.control.service;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.yenlien.traceyun.control.dao.*;
import com.yenlien.traceyun.control.entity.*;
import com.yenlien.traceyun.control.interceptor.UserAuthUtil;
import com.yenlien.traceyun.webase.exception.BusinessException;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.transaction.Transactional;
import java.text.DecimalFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;

import static com.yenlien.traceyun.common.utils.Tools.DATE_TIME_FORMATTER;

@Service
public class CMSService {

    @Autowired
    private FruitBannerDao bannerDao;
    @Autowired
    private ArticleDao articleDao;
    @Autowired
    private FruitRecallDao fruitRecallDao;
    @Autowired
    private ExpertDao expertDao;
    @Autowired
    private FruitTownDao fruitTownDao;

    public static DecimalFormat df = new DecimalFormat("###.##");

    // 仅添加镇信息
    public FruitTown saveFruitTown1(FruitTown fruitTown) {
        String time = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        // 该年度存在则覆盖
        List<FruitTown> existList = fruitTownDao.findByNameAndAnnual(fruitTown.getName(), fruitTown.getAnnual());
        if(CollectionUtils.isNotEmpty(existList))
            fruitTown.setId(existList.get(0).getId());
        if (StringUtils.isBlank(fruitTown.getId())) {
            fruitTown.setCreateTime(time);
        }
        return fruitTownDao.save(fruitTown);
    }



    // 仅添加村信息，镇信息自动核算
    public FruitTown saveFruitTown(FruitTown fruitTown) {
        String time = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        // 该年度存在则覆盖
        List<FruitTown> existList = fruitTownDao.findByNameAndAnnual(fruitTown.getName(), fruitTown.getAnnual());
        if(CollectionUtils.isNotEmpty(existList))
            fruitTown.setId(existList.get(0).getId());

        // 该年度上级是否已有记录
        List<FruitTown> townExistList = fruitTownDao.findByNameAndAnnual(fruitTown.getParentName(), fruitTown.getAnnual());
        FruitTown town;
        JSONArray jsonArray = new JSONArray();
        if(CollectionUtils.isNotEmpty(townExistList)){
            // 存在则更新记录
            town = townExistList.get(0);
            List<FruitTown> villageList = fruitTownDao.findByParentId(town.getId());
            Double area = 0D;
            Double areaFruiting = 0D;
            Double prodNum = 0D;
            Double prodVal = 0D;
            for(FruitTown village : villageList){
                area += village.getArea();
                areaFruiting += village.getAreaFruiting();
                prodNum += village.getProdNum();
                prodVal += village.getProdVal();
                if(StringUtils.isNotBlank(village.getInfo())){
                    JSONArray array = JSONObject.parseArray(village.getInfo());
                    if(CollectionUtils.isNotEmpty(jsonArray))
                        jsonArray.addAll(array);
                }
            }
            town.setArea(area);
            town.setAreaFruiting(areaFruiting);
            town.setProdNum(prodNum);
            town.setProdVal(prodVal);
            town.setFruitingRatio(df.format((areaFruiting / area) * 100) + "%");
            town.setInfo(JSONObject.toJSONString(jsonArray));
        }else {
            town = new FruitTown();
            BeanUtils.copyProperties(fruitTown, town);
            town.setType("镇");
            town.setParentId(null);
            town.setParentName(null);
            town.setInfo(JSONObject.toJSONString(jsonArray));
        }
        fruitTownDao.save(town);
        if (StringUtils.isBlank(fruitTown.getId())) {
            fruitTown.setCreateTime(time);
        }
        return fruitTownDao.save(fruitTown);
    }









    public List<FruitTown> findAllFruitTown() {
        return fruitTownDao.findAll();
    }


    public FruitTown findFruitTownById(String id) {
        FruitTown fruitTown = fruitTownDao.findById(id).orElseThrow(() -> new BusinessException("该条数据不存在"));
        fruitTown.setVillageList(fruitTownDao.findByParentId(id));
        return fruitTown;
    }





    public JSONObject findAllFruitTownExpert() {
        JSONObject json = new JSONObject();
        json.put("fruitTownList", fruitTownDao.findByType("镇"));
        json.put("expertList", expertDao.findAll());
        return json;
    }


    @Transactional
    public void delFruitTownById(String id) {
//        FruitTown fruitTown = fruitTownDao.findById(id).orElseThrow(() -> new BusinessException("该条数据不存在"));
//        if("镇".equals(fruitTown)){
//            fruitTownDao.delByParentId(id);
//        }
        fruitTownDao.delByParentId(id);
    }


    public List<FruitTown> findFruitTownList(FruitTown fruitTown) {
        return fruitTownDao.findAll((Root<FruitTown> root, CriteriaQuery<?> query, CriteriaBuilder cb) -> {
            List<Predicate> list = new ArrayList<>();
            if(StringUtils.isNotBlank(fruitTown.getName()))
                list.add(cb.like(root.get("name"), "%" + fruitTown.getName() + "%"));
            if(StringUtils.isNotBlank(fruitTown.getType()))
                list.add(cb.equal(root.get("type"), fruitTown.getType()));
            return cb.and(list.toArray(new Predicate[list.size()]));
        });
    }

    public List<FruitTown> findByNameType(String name, String type) {
        return fruitTownDao.findByNameType(name, type);
    }


    public Page<FruitTown> findFruitTownPage(FruitTown fruitTown) {
        Pageable pageable = PageRequest.of(fruitTown.getPage(), fruitTown.getPageNum(), Sort.Direction.DESC, ("createTime"));
        return fruitTownDao.findAll((Root<FruitTown> root, CriteriaQuery<?> query, CriteriaBuilder cb) -> {
            List<Predicate> list = new ArrayList<>();
            if(StringUtils.isNotBlank(fruitTown.getName()))
                list.add(cb.like(root.get("name"), "%" + fruitTown.getName() + "%"));
            if(StringUtils.isNotBlank(fruitTown.getType()))
                list.add(cb.equal(root.get("type"), fruitTown.getType()));
            return cb.and(list.toArray(new Predicate[list.size()]));
        }, pageable);
    }









    public Expert saveExpert(Expert expert) {
        String time = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        if (StringUtils.isBlank(expert.getId())) {
            expert.setCreateTime(time);
            expert.setUpdateTime(time);
            expert.setCompanyId(UserAuthUtil.getLoginUser().getCompanyId());
        }else {
            expert.setUpdateTime(time);
        }
        return expertDao.save(expert);
    }

    public List<Expert> findAllExpert() {
        return expertDao.findAll();
    }

    public void delExpertById(String id) {
        expertDao.deleteById(id);
    }

    public void delBannerById(String id) {
        bannerDao.deleteById(id);
    }

    public List<Expert> findExpertList(Expert expert) {
        return expertDao.findAll((Root<Expert> root, CriteriaQuery<?> query, CriteriaBuilder cb) -> {
            List<Predicate> list = new ArrayList<>();
            if(StringUtils.isNotBlank(expert.getType()))
                list.add(cb.equal(root.get("type"), expert.getType()));
            return cb.and(list.toArray(new Predicate[list.size()]));
        });
    }

    public Page<Expert> findExpertPage(Expert expert) {
        Pageable pageable = PageRequest.of(expert.getPage(), expert.getPageNum(), Sort.Direction.DESC, ("createTime"));
        return expertDao.findAll((Root<Expert> root, CriteriaQuery<?> query, CriteriaBuilder cb) -> {
            List<Predicate> list = new ArrayList<>();
            if(StringUtils.isNotBlank(expert.getType()))
                list.add(cb.equal(root.get("type"), expert.getType()));
            return cb.and(list.toArray(new Predicate[list.size()]));
        }, pageable);
    }






    public FruitRecall saveRecall(FruitRecall fruitRecall) {
        if (StringUtils.isBlank(fruitRecall.getId())) {
            fruitRecall.setCreateTime(LocalDateTime.now().format(DATE_TIME_FORMATTER));
            fruitRecall.setCompanyId(UserAuthUtil.getLoginUser().getCompanyId());
        }
        return fruitRecallDao.save(fruitRecall);
    }





    public FruitBanner saveBanner(FruitBanner fruitBanner) {
        if (StringUtils.isBlank(fruitBanner.getId())) {
            fruitBanner.setCreateTime(LocalDateTime.now().format(DATE_TIME_FORMATTER));
            fruitBanner.setCompanyId(UserAuthUtil.getLoginUser().getCompanyId());
        }
        return bannerDao.save(fruitBanner);
    }

    public Article saveArticle(Article article) {
        String dateTime = LocalDateTime.now().format(DATE_TIME_FORMATTER);
        if(StringUtils.isBlank(article.getId())){
            article.setViewNum(0);
            article.setState("1");
            article.setCreateTime(dateTime);
            article.setLastUpdateTime(dateTime);
            article.setCompanyId(UserAuthUtil.getLoginUser().getCompanyId());
        }else {
            article.setLastUpdateTime(dateTime);
            if("2".equals(article.getState())){
                article.setPublisher(UserAuthUtil.getLoginUser().getUsername());
            }
        }
        return articleDao.save(article);
    }



    public Page<FruitBanner> findBannerPage(FruitBanner fruitBanner) {
        if(StringUtils.isBlank(fruitBanner.getCompanyId())){
            fruitBanner.setCompanyId(UserAuthUtil.getLoginUser().getCompanyId());
        }
        Pageable pageable = PageRequest.of(fruitBanner.getPage(), fruitBanner.getPageNum(), Sort.Direction.DESC, ("createTime"));
        return bannerDao.findAll((Root<FruitBanner> root, CriteriaQuery<?> query, CriteriaBuilder cb) -> {
            List<Predicate> list = new ArrayList<>();
            if(StringUtils.isNotBlank(fruitBanner.getCompanyId()))
                list.add(cb.equal(root.get("companyId"), fruitBanner.getCompanyId()));
            if(StringUtils.isNotBlank(fruitBanner.getType()))
                list.add(cb.equal(root.get("type"), fruitBanner.getType()));
            return cb.and(list.toArray(new Predicate[list.size()]));
        }, pageable);
    }



    public List<FruitBanner> findBannerList(FruitBanner fruitBanner) {
        return bannerDao.findAll((Root<FruitBanner> root, CriteriaQuery<?> query, CriteriaBuilder cb) -> {
            List<Predicate> list = new ArrayList<>();
            if(StringUtils.isNotBlank(fruitBanner.getType()))
                list.add(cb.equal(root.get("type"), fruitBanner.getType()));
            return cb.and(list.toArray(new Predicate[list.size()]));
        });
    }

    public Page<FruitRecall> findRecallList(FruitRecall fruitRecall) {
        Pageable pageable = PageRequest.of(fruitRecall.getPage(), fruitRecall.getPageNum(), Sort.Direction.DESC, ("createTime"));
        return fruitRecallDao.findAll((Root<FruitRecall> root, CriteriaQuery<?> query, CriteriaBuilder cb) -> {
            List<Predicate> list = new ArrayList<>();
            if(StringUtils.isNotBlank(fruitRecall.getCompanyId()))
                list.add(cb.equal(root.get("companyId"), fruitRecall.getCompanyId()));
            if(StringUtils.isNotBlank(fruitRecall.getProductName()))
                list.add(cb.like(root.get("productName"), "%" + fruitRecall.getProductName() + "%"));
            if(StringUtils.isNotBlank(fruitRecall.getBatch()))
                list.add(cb.like(root.get("batch"), fruitRecall.getBatch()));
            return cb.and(list.toArray(new Predicate[list.size()]));
        }, pageable);
    }

    public Page<Article> findContentList(Article article) {
        Pageable pageable = PageRequest.of(article.getPage(), article.getPageNum(), Sort.Direction.DESC, ("createTime"));
        return articleDao.findAll((Root<Article> root, CriteriaQuery<?> query, CriteriaBuilder cb) -> {
            List<Predicate> listAnd = new ArrayList<>();
            if(StringUtils.isNotBlank(article.getType()))
                listAnd.add(cb.equal(root.get("type"), article.getType()));
            if(StringUtils.isNotBlank(article.getState()))
                listAnd.add(cb.equal(root.get("state"), article.getState()));
            if(article.getHomeShow() != null)
                listAnd.add(cb.equal(root.get("homeShow"), article.getHomeShow()));
            if(article.getHotspot() != null)
                listAnd.add(cb.equal(root.get("hotspot"), article.getHotspot()));
            if(StringUtils.isNotBlank(article.getPublisher()))
                listAnd.add(cb.like(root.get("publisher"), "%" +article.getPublisher() + "%"));
            return cb.and(listAnd.toArray(new Predicate[listAnd.size()]));
        }, pageable);
    }


    public Object getContentList(Article article) {
        if("1".equals(article.getPageType())){
            Pageable pageable = PageRequest.of(article.getPage(), article.getPageNum(), Sort.Direction.DESC, ("createTime"));
            return articleDao.findAll((Root<Article> root, CriteriaQuery<?> query, CriteriaBuilder cb) -> {
                return genArticlePredicate(root, cb, article);
            }, pageable);
        }else {
            return articleDao.findAll((Root<Article> root, CriteriaQuery<?> query, CriteriaBuilder cb) -> {
                return genArticlePredicate(root, cb, article);
            });
        }
    }

    public Predicate genArticlePredicate(Root<Article> root, CriteriaBuilder cb, Article article){
        List<Predicate> listAnd = new ArrayList<>();
        if(StringUtils.isNotBlank(article.getCompanyId()))
            listAnd.add(cb.equal(root.get("companyId"), article.getCompanyId()));
        if(StringUtils.isNotBlank(article.getType()))
            listAnd.add(cb.equal(root.get("type"), article.getType()));
        if(StringUtils.isNotBlank(article.getState()))
            listAnd.add(cb.equal(root.get("state"), article.getState()));
        if(article.getHomeShow() != null)
            listAnd.add(cb.equal(root.get("homeShow"), article.getHomeShow()));
        if(article.getHotspot() != null)
            listAnd.add(cb.equal(root.get("hotspot"), article.getHotspot()));
        if(StringUtils.isNotBlank(article.getPublisher()))
            listAnd.add(cb.like(root.get("publisher"), "%" +article.getPublisher() + "%"));
        return cb.and(listAnd.toArray(new Predicate[listAnd.size()]));
    }






    public List<JSONObject> findArticleDown(String companyId) {
       if(StringUtils.isBlank(companyId))
           companyId = UserAuthUtil.getLoginUser().getCompanyId();
       if(StringUtils.isBlank(companyId)){
           return articleDao.getIdName();
       }
        return articleDao.getIdNameByState(companyId);
    }

    public Article state(String id, String state) {
        Article article = articleDao.findById(id).orElseThrow(() -> new BusinessException("该文章不存在"));
        article.setState(state);
        return articleDao.save(article);
    }

    public Article findArticleById(String id) {
        Article article = articleDao.findById(id).orElseThrow(() -> new BusinessException("该文章不存在"));
        Integer viewNum = article.getViewNum();
        if(viewNum == null)
            viewNum = 1;
        else
            viewNum += 1;
        article.setViewNum(viewNum);
        return articleDao.save(article);
    }

    public FruitRecall findRecallById(String id) {
        return fruitRecallDao.findById(id).orElseThrow(() -> new BusinessException("该召回信息不存在"));
    }









}
